package com.xpec.cipher.tals;

import java.security.MessageDigest;

import org.jboss.netty.buffer.ChannelBuffer;

public class PseudoRandom {

	private static MessageDigest md = null;

	private static MessageDigest sha = null;

	private static int defaultRandomSize = 48;

	private static int stepSize = 16;

	private static byte[][] charKey = { "1".getBytes(), "2".getBytes(),
			"3".getBytes(), "4".getBytes() };

	private static MessageDigest getMD5Instance() {
		try {
			if (md == null)
				md = MessageDigest.getInstance("MD5");
			return md;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}

	private static MessageDigest getSHA1Instance() {
		try {
			if (sha == null)
				sha = MessageDigest.getInstance("SHA-1");
			return sha;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}

	public static byte[] generatePRG(byte[] key, byte[] randomA,
			byte[] randomB, int bytes) {
		MessageDigest md5dg = getMD5Instance();
		MessageDigest sha1dg = getSHA1Instance();
		if (md5dg == null)
			return null;
		// Any Synchronized Problem?
		byte[] result = new byte[bytes];
		byte[] random = xorArray(randomA, randomB);
		for (int i = 0; i < bytes / stepSize; i++) {
			// 保证线程安全
			byte[] sha1rst = null;
			synchronized (sha) {
				sha1rst = sha1dg.digest(orArray(charKey[i], key, random));
			}
			byte[] text = null;
			synchronized (md) {
				text = md5dg.digest(orArray(key, sha1rst, new byte[0]));
			}
			for (int j = 0; j < stepSize; j++) {
				result[i * stepSize + j] = text[j];
			}
		}
		return result;
	}

	public static byte[] generatePRG(byte[] key, byte[] randomA, byte[] randomB) {
		return generatePRG(key, randomA, randomB, defaultRandomSize);
	}

	public static byte[] xorArray(byte[] a, byte[] b) {
		if (b.length < a.length) {
			// better to throw exception
			System.out.println("length of byte [] b must be >= byte [] a");
			return null;
		}
		byte[] c = new byte[a.length];
		for (int i = 0; i < a.length; i++) {
			c[i] = (byte) (a[i] ^ b[i]);
		}
		return c;
	}

	/**
	 * 将两个byte右对齐做xor运算，最后的结果数组长度为a、b中较长数组的长度。
	 * 
	 * @param a
	 * @param b
	 * @return
	 */

	public static ChannelBuffer xorArray(ChannelBuffer a, ChannelBuffer b)
	{
		ChannelBuffer lShortArray = null, lLongArray = null;
		
		if (a.readableBytes() >= b.readableBytes()) 
		{
			lLongArray = a;
			lShortArray = b;
		} 
		else 
		{
			lLongArray = b;
			lShortArray = a;
		}
		
		ChannelBuffer lFinalArray = lLongArray.copy();
		for (int i = 0; i < lShortArray.readableBytes(); i++) 
		{
			byte value = (byte)	(lFinalArray.getByte(lFinalArray.readableBytes()-i-1) 
								^ lShortArray.getByte(lShortArray.readableBytes()-i-1));
			lFinalArray.setByte(lFinalArray.readableBytes()-i-1, value);
		}
		return lFinalArray;
	}
	
	public static byte[] xorArrayLinYue(byte[] a, byte[] b) {
		byte[] lShortArray = null;
		byte[] lLongArray = null;
		if (a.length >= b.length) {
			lLongArray = a;
			lShortArray = b;
		} else {
			lLongArray = b;
			lShortArray = a;
		}
		byte[] lFinalArray = lLongArray.clone();
		for (int i = 0; i < lShortArray.length; i++) {
			lFinalArray[lFinalArray.length - i - 1] = (byte) (lFinalArray[lFinalArray.length
					- i - 1] ^ lShortArray[lShortArray.length - i - 1]);
		}
		return lFinalArray;
	}

	public static byte[] orArray(byte[] a, byte[] b, byte[] c) {
		int maxLen = a.length;
		if (maxLen < b.length)
			maxLen = b.length;
		if (maxLen < c.length)
			maxLen = c.length;

		byte[] rst = new byte[maxLen];

		for (int i = 0; i < maxLen; i++) {
			byte va, vb, vc;

			if (maxLen - i > a.length)
				va = 0;
			else
				va = a[a.length - maxLen + i];

			if (maxLen - i > b.length)
				vb = 0;
			else
				vb = b[b.length - maxLen + i];

			if (maxLen - i > c.length)
				vc = 0;
			else
				vc = c[c.length - maxLen + i];

			rst[i] = (byte) (va | vb | vc);
		}

		return rst;
	}

}
